package com.todod.base.module.infra.service.baseofficialletter;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
import com.mzt.logapi.starter.annotation.LogRecord;
import com.todod.base.framework.security.core.util.SecurityFrameworkUtils;
import com.todod.base.framework.web.core.util.WebFrameworkUtils;
import com.todod.base.module.infra.dal.dataobject.baseofficialletter.BaseOfficialLetterDetailDO;
import com.todod.base.module.infra.dal.dataobject.baseofficialletter.BaseOfficialLetterFileDO;
import com.todod.base.module.infra.dal.dataobject.baseofficialletter.BaseOfficialLetterRecordsDO;
import com.todod.base.module.infra.dal.dataobject.file.FileDO;
import com.todod.base.module.infra.dal.mysql.baseofficialletter.BaseOfficialLetterDetailMapper;
import com.todod.base.module.infra.dal.mysql.baseofficialletter.BaseOfficialLetterFileMapper;
import com.todod.base.module.infra.dal.mysql.baseofficialletter.BaseOfficialLetterRecordsMapper;
import com.todod.base.module.infra.dal.mysql.file.FileMapper;
import com.todod.base.module.infra.enums.untils.MinIoUtils;
import com.todod.base.module.system.api.permission.PermissionApi;
import com.todod.base.module.system.api.user.AdminUserApi;
import com.todod.base.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import com.todod.base.module.infra.controller.admin.baseofficialletter.vo.*;
import com.todod.base.module.infra.dal.dataobject.baseofficialletter.BaseOfficialLetterDO;
import com.todod.base.framework.common.pojo.PageResult;
import com.todod.base.framework.common.util.object.BeanUtils;

import com.todod.base.module.infra.dal.mysql.baseofficialletter.BaseOfficialLetterMapper;

import static com.todod.base.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.todod.base.module.infra.enums.ErrorCodeConstants.*;
import static com.todod.base.module.infra.enums.LogRecordConstants.*;

/**
 * 公函 Service 实现类
 *
 * @author 平台管理员
 */
@Service
@Validated
public class BaseOfficialLetterServiceImpl implements BaseOfficialLetterService {

    @Resource
    private BaseOfficialLetterMapper baseOfficialLetterMapper;

    @Resource
    private BaseOfficialLetterDetailMapper baseOfficialLetterDetailMapper;

    @Resource
    private BaseOfficialLetterFileMapper baseOfficialLetterFileMapper;

    @Resource
    private BaseOfficialLetterRecordsMapper baseOfficialLetterRecordsMapper;
    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private PermissionApi permissionApi;


    @Resource
    private FileMapper fileMapper;
    // 存储桶名称
    @Value("${minio.bucketName}")
    private String bucketName;
    @Autowired
    private MinIoUtils minIoUtils;

    public static final String PROCESS_KEY = "base_official_letter";

    @Override
    @LogRecord(type = BASE_OFFICIAL_LETTER_TYPE, subType = BASE_OFFICIAL_LETTER_CREATE_SUB_TYPE, bizNo = "{{#baseOfficialLetter.id}}",
            success = BASE_OFFICIAL_LETTER_CREATE_SUCCESS)
    public Long createBaseOfficialLetter(BaseOfficialLetterSaveReqVO createReqVO) {
        // 插入
        BaseOfficialLetterDO baseOfficialLetter = BeanUtils.toBean(createReqVO, BaseOfficialLetterDO.class);
        baseOfficialLetterMapper.insert(baseOfficialLetter);

        if (createReqVO.getDetailData() != null && createReqVO.getDetailData().size() > 0) {
            for (BaseOfficialLetterDetailDO detailDO : createReqVO.getDetailData()) {
                BaseOfficialLetterDetailDO baseOfficialLetterDetail = new BaseOfficialLetterDetailDO();
                baseOfficialLetterDetail.setOfficialLetterId(baseOfficialLetter.getId());
                baseOfficialLetterDetail.setUserId(detailDO.getUserId());
                baseOfficialLetterDetail.setUserName(detailDO.getUserName());
                baseOfficialLetterDetail.setTotalViewNum(detailDO.getTotalViewNum());
                baseOfficialLetterDetail.setStatus(detailDO.getStatus());
                baseOfficialLetterDetailMapper.insert(baseOfficialLetterDetail);
            }
        }

        if (createReqVO.getFileData() != null && createReqVO.getFileData().size() > 0) {
            for (BaseOfficialLetterFileDO fileDO : createReqVO.getFileData()) {
                BaseOfficialLetterFileDO baseOfficialLetterFile = new BaseOfficialLetterFileDO();
                baseOfficialLetterFile.setOfficialLetterId(baseOfficialLetter.getId());
                baseOfficialLetterFile.setFileId(fileDO.getFileId());
                baseOfficialLetterFileMapper.insert(baseOfficialLetterFile);
            }
        }

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("baseOfficialLetter", baseOfficialLetter);
        this.switchOrderStatus(baseOfficialLetter);

        // 返回
        return baseOfficialLetter.getId();
    }

    void switchOrderStatus(BaseOfficialLetterDO baseOfficialLetter) {
        switch (baseOfficialLetter.getStatus()) {
            case 1: // 待审核，修改状态为2，已签字待审批，修改状态为5，添加提交时间
                this.submitToBpm(baseOfficialLetter, baseOfficialLetter.getId());
                break;
            case 2: // 已审核通过，修改状态为2，添加审核通过时间，向学员关联课程表中加入课时数据
                break;
            case 3: // 已审核驳回，修改状态为3
                break;
            default: // 草稿
                break;
        }
    }

    private void submitToBpm(BaseOfficialLetterDO baseOfficialLetter, Long id) {
        // 提交流程
        Long userId = WebFrameworkUtils.getLoginUserId();

        int role = 0;
        {
            Boolean exist = permissionApi.hasAnyRoles(userId, "yx").getData();
            if(exist && !permissionApi.hasAnyRoles(userId, "yx_manage").getData()){
                role = 1;
            }
        }
        {
            Boolean exist = permissionApi.hasAnyRoles(userId, "xf").getData();
            if(exist && !permissionApi.hasAnyRoles(userId, "xf_manage").getData()){
                role = 2;
            }
        }
        {
            Boolean exist = permissionApi.hasAnyRoles(userId, "jw").getData();
            if(exist && !permissionApi.hasAnyRoles(userId, "jw_manage").getData()){
                role = 3;
            }
        }

        Map<String, Object> proVar = new HashMap<>();
        proVar.put("role", role);
    }

    @Override
    @LogRecord(type = BASE_OFFICIAL_LETTER_TYPE, subType = BASE_OFFICIAL_LETTER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = BASE_OFFICIAL_LETTER_UPDATE_SUCCESS)
    public void updateBaseOfficialLetter(BaseOfficialLetterSaveReqVO updateReqVO) {
        // 校验存在
        validateBaseOfficialLetterExists(updateReqVO.getId());
        BaseOfficialLetterDO oldBaseOfficialLetter = baseOfficialLetterMapper.selectById(updateReqVO.getId());
        // 更新
        BaseOfficialLetterDO updateObj = BeanUtils.toBean(updateReqVO, BaseOfficialLetterDO.class);
        baseOfficialLetterMapper.updateById(updateObj);

        List<BaseOfficialLetterDetailDO> baseOfficialLetterDetailList = baseOfficialLetterDetailMapper.getSimpleLetterDetailList(updateReqVO.getId());
        for (BaseOfficialLetterDetailDO detailDO : baseOfficialLetterDetailList) {
            baseOfficialLetterDetailMapper.deleteById(detailDO.getId());
        }

        if (updateReqVO.getDetailData() != null && updateReqVO.getDetailData().size() > 0) {
            for (BaseOfficialLetterDetailDO detailDO : updateReqVO.getDetailData()) {
                BaseOfficialLetterDetailDO baseOfficialLetterDetail = new BaseOfficialLetterDetailDO();
                baseOfficialLetterDetail.setOfficialLetterId(updateObj.getId());
                baseOfficialLetterDetail.setUserId(detailDO.getUserId());
                baseOfficialLetterDetail.setUserName(detailDO.getUserName());
                baseOfficialLetterDetail.setTotalViewNum(detailDO.getTotalViewNum());
                baseOfficialLetterDetail.setStatus(detailDO.getStatus());
                baseOfficialLetterDetailMapper.insert(baseOfficialLetterDetail);
            }
        }

        List<BaseOfficialLetterFileDO> baseOfficialLetterFileList = baseOfficialLetterFileMapper.getSimpleLetterFileList(updateReqVO.getId());
        for (BaseOfficialLetterFileDO fileDO : baseOfficialLetterFileList) {
            baseOfficialLetterFileMapper.deleteById(fileDO.getId());
        }

        if (updateReqVO.getFileData() != null && updateReqVO.getFileData().size() > 0) {
            for (BaseOfficialLetterFileDO fileDO : updateReqVO.getFileData()) {
                BaseOfficialLetterFileDO baseOfficialLetterFile = new BaseOfficialLetterFileDO();
                baseOfficialLetterFile.setOfficialLetterId(updateObj.getId());
                baseOfficialLetterFile.setFileId(fileDO.getFileId());
                baseOfficialLetterFileMapper.insert(baseOfficialLetterFile);
            }
        }

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBaseOfficialLetter, BaseOfficialLetterSaveReqVO.class));
        LogRecordContext.putVariable("baseOfficialLetter", oldBaseOfficialLetter);

        this.switchOrderStatus(updateObj);
    }

    @Override
    @LogRecord(type = BASE_OFFICIAL_LETTER_TYPE, subType = BASE_OFFICIAL_LETTER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
            success = BASE_OFFICIAL_LETTER_DELETE_SUCCESS)
    public void deleteBaseOfficialLetter(Long id) {
        // 校验存在
        validateBaseOfficialLetterExists(id);

        List<BaseOfficialLetterDetailDO> baseOfficialLetterDetailList = baseOfficialLetterDetailMapper.getSimpleLetterDetailList(id);
        for (BaseOfficialLetterDetailDO detailDO : baseOfficialLetterDetailList) {
            baseOfficialLetterDetailMapper.deleteById(detailDO.getId());
        }

        List<BaseOfficialLetterFileDO> baseOfficialLetterFileList = baseOfficialLetterFileMapper.getSimpleLetterFileList(id);
        for (BaseOfficialLetterFileDO baseOfficialLetterFileDO : baseOfficialLetterFileList) {

            FileDO fileDO = fileMapper.selectById(baseOfficialLetterFileDO.getFileId());
            minIoUtils.removeObject(bucketName, fileDO.getPath());

            fileMapper.deleteById(baseOfficialLetterFileDO.getFileId());

            baseOfficialLetterFileMapper.deleteById(fileDO.getId());
        }

        // 删除
        baseOfficialLetterMapper.deleteById(id);
    }

    private void validateBaseOfficialLetterExists(Long id) {
        if (baseOfficialLetterMapper.selectById(id) == null) {
            throw exception(BASE_OFFICIAL_LETTER_NOT_EXISTS);
        }
    }

    @Override
    public BaseOfficialLetterDO getBaseOfficialLetter(Long id) {
        return baseOfficialLetterMapper.selectById(id);
    }

    @Override
    public PageResult<BaseOfficialLetterDO> getBaseOfficialLetterPage(BaseOfficialLetterPageReqVO pageReqVO) {
        return baseOfficialLetterMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<BaseOfficialLetterDO> getEffectOfficialLetterPage(BaseOfficialLetterPageReqVO pageReqVO) {
        IPage<BaseOfficialLetterDO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        baseOfficialLetterMapper.getEffectOfficialLetterPage(page, pageReqVO);
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public PageResult<BaseOfficialLetterDO> getInvalidOfficialLetterPage(BaseOfficialLetterPageReqVO pageReqVO) {
        return baseOfficialLetterMapper.getInvalidOfficialLetterPage(pageReqVO);
    }

    @Override
    @LogRecord(type = BASE_OFFICIAL_LETTER_TYPE, subType = BASE_OFFICIAL_LETTER_VIEW_SUB_TYPE, bizNo = "{{#baseOfficialLetter.id}}",
            success = BASE_OFFICIAL_LETTER_VIEW_RECORDS_SUCCESS)
    public Long updateLetterDetail(BaseOfficialLetterDetailSaveReqVO createReqVO) {
        BaseOfficialLetterDetailDO baseOfficialLetterDetail = baseOfficialLetterDetailMapper.selectById(createReqVO.getId());

        baseOfficialLetterDetail.setStatus(createReqVO.getStatus());

        if (baseOfficialLetterDetail.getFirstViewTime() == null) {
            baseOfficialLetterDetail.setFirstViewTime(LocalDateTime.now());
        }
        baseOfficialLetterDetail.setLastViewTime(LocalDateTime.now());

        if (baseOfficialLetterDetail.getTotalViewNum() != null) {
            baseOfficialLetterDetail.setTotalViewNum(baseOfficialLetterDetail.getTotalViewNum() + createReqVO.getTotalViewNum());
        } else {
            baseOfficialLetterDetail.setTotalViewNum(createReqVO.getTotalViewNum());
        }
        baseOfficialLetterDetailMapper.updateById(baseOfficialLetterDetail);

        BaseOfficialLetterDO oldBaseOfficialLetter = baseOfficialLetterMapper.selectById(baseOfficialLetterDetail.getOfficialLetterId());

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("baseOfficialLetter", oldBaseOfficialLetter);

        return createReqVO.getId();
    }

    @Override
    @LogRecord(type = BASE_OFFICIAL_LETTER_TYPE, subType = BASE_OFFICIAL_LETTER_SUBMIT_SUB_TYPE, bizNo = "{{#baseOfficialLetter.id}}",
            success = BASE_OFFICIAL_LETTER_SUBMIT_RECORDS_SUCCESS)
    public Long submitOfficialLetter(BaseOfficialLetterSubmitReqVO submitReqVO) {
        for (Long id : submitReqVO.getIds()) {
            BaseOfficialLetterDO oldBaseOfficialLetter = baseOfficialLetterMapper.selectById(id);

            oldBaseOfficialLetter.setStatus(submitReqVO.getStatus());
            oldBaseOfficialLetter.setUpdateTime(LocalDateTime.now());
            oldBaseOfficialLetter.setUpdater(SecurityFrameworkUtils.getLoginUserId().toString());
            baseOfficialLetterMapper.updateById(oldBaseOfficialLetter);

            // 3. 记录操作日志上下文
            LogRecordContext.putVariable("baseOfficialLetter", oldBaseOfficialLetter);
        }

        return 1l;
    }

    @Override
    public void updateOfficialDetail(BaseOfficialLetterDetailsSaveReqVO updateReqVO) {
        List<BaseOfficialLetterDetailDO> baseOfficialLetterDetailList = baseOfficialLetterDetailMapper.getSimpleLetterDetailList(updateReqVO.getOfficialLetterId());

        List<BaseOfficialLetterDetailDO> detailData = updateReqVO.getDetailData();

        if (updateReqVO.getDetailData() != null && updateReqVO.getDetailData().size() > 0) {
            for (BaseOfficialLetterDetailDO detailDO : updateReqVO.getDetailData()) {
                if (baseOfficialLetterDetailList != null && baseOfficialLetterDetailList.size() > 0) {
                    // 循环前台传来的公函人员列表，判断当前人员是否在数据库中存在，避免出现重复人员
                    Optional<BaseOfficialLetterDetailDO> optional = baseOfficialLetterDetailList.stream().filter(x -> x.getUserId().equals(detailDO.getUserId())).findAny();
                    if (!optional.isPresent()) {
                        BaseOfficialLetterDetailDO baseOfficialLetterDetail = new BaseOfficialLetterDetailDO();
                        baseOfficialLetterDetail.setOfficialLetterId(updateReqVO.getOfficialLetterId());
                        baseOfficialLetterDetail.setUserId(detailDO.getUserId());
                        baseOfficialLetterDetail.setUserName(detailDO.getUserName());
                        baseOfficialLetterDetail.setTotalViewNum(detailDO.getTotalViewNum());
                        baseOfficialLetterDetail.setStatus(detailDO.getStatus());
                        baseOfficialLetterDetailMapper.insert(baseOfficialLetterDetail);
                    }
                } else {
                    BaseOfficialLetterDetailDO baseOfficialLetterDetail = new BaseOfficialLetterDetailDO();
                    baseOfficialLetterDetail.setOfficialLetterId(updateReqVO.getOfficialLetterId());
                    baseOfficialLetterDetail.setUserId(detailDO.getUserId());
                    baseOfficialLetterDetail.setUserName(detailDO.getUserName());
                    baseOfficialLetterDetail.setTotalViewNum(detailDO.getTotalViewNum());
                    baseOfficialLetterDetail.setStatus(detailDO.getStatus());
                    baseOfficialLetterDetailMapper.insert(baseOfficialLetterDetail);
                }
            }

            // 循环数据库获取的公函人员列表，判断当前人员是否在前台数据中存在，如果不存在说明当前人员已被删除，需要删除数据库数据
            for (BaseOfficialLetterDetailDO detailDO : baseOfficialLetterDetailList) {
                Optional<BaseOfficialLetterDetailDO> optional = detailData.stream().filter(x -> x.getUserId().equals(detailDO.getUserId())).findAny();
                if (!optional.isPresent()) {
                    baseOfficialLetterDetailMapper.deleteById(detailDO.getId());
                }
            }
        }
    }

    @Override
    @LogRecord(type = BASE_OFFICIAL_LETTER_TYPE, subType = BASE_OFFICIAL_LETTER_RECORDS_CREATE_SUB_TYPE, bizNo = "{{#baseOfficialLetter.id}}",
            success = BASE_OFFICIAL_LETTER_RECORDS_CREATE_SUCCESS)
    public Long createBaseOfficialRecord(BaseOfficialLetterRecordsSaveReqVO createReqVO) {

        BaseOfficialLetterRecordsDO baseOfficialLetterRecords = BeanUtils.toBean(createReqVO, BaseOfficialLetterRecordsDO.class);

        BaseOfficialLetterDO oldBaseOfficialLetter = baseOfficialLetterMapper.selectById(createReqVO.getOfficialLetterId());
        oldBaseOfficialLetter.setStatus(createReqVO.getApproveResult());
        oldBaseOfficialLetter.setUpdater(SecurityFrameworkUtils.getLoginUserId().toString());
        oldBaseOfficialLetter.setUpdateTime(LocalDateTime.now());
        if (createReqVO.getApproveResult() == 2) {
            oldBaseOfficialLetter.setPublishTime(LocalDateTime.now());
        }

        baseOfficialLetterMapper.updateById(oldBaseOfficialLetter);

        baseOfficialLetterRecordsMapper.insert(baseOfficialLetterRecords);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("baseOfficialLetter", oldBaseOfficialLetter);

        return baseOfficialLetterRecords.getId();
    }

}